﻿/*
 * Copyright (c) Seagull Consulting, Inc. All rights reserved. See License.txt in the project root for license information.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace SeagullConsulting.MvcAjaxControls.Web.UI.Helpers
{
	#region enums
	public enum WhereOperation
	{
		Contains,
		NotEqual,
		GreaterThan,
		LessThan,
		GreaterThanOrEqual,
		LessThanOrEqual,
		Equal

	}
	public enum ExpressionSortDirection
	{
		Ascending,
		Descending
	}
	#endregion

	#region ExpressionBuilder
	public class ExpressionBuilder<T> where T : class
	{
		private readonly Type entityType;
		private readonly ParameterExpression parameter;
		private readonly MemberExpression memberExpression;
		private readonly ConstantExpression propertyValue;

		public ExpressionBuilder(string propertyName, string propertyValue)
		{
			entityType = typeof(T);
			parameter = Expression.Parameter(entityType);
			memberExpression = null;
			foreach (var property in propertyName.Split('.'))
				memberExpression = MemberExpression.Property(memberExpression ?? (parameter as Expression), property);
			this.propertyValue = Expression.Constant(propertyValue);
		}

		public Func<T, bool> Where(WhereOperation whereOperation)
		{
			Expression body;
			Expression<Func<T, bool>> whereExpression;

			switch (whereOperation)
			{
				case WhereOperation.Contains:
					body = Expression.Call(memberExpression, typeof(string).GetMethod("Contains"), propertyValue);
					break;
				case WhereOperation.GreaterThan:
					body = Expression.GreaterThan(memberExpression, propertyValue);
					break;
				case WhereOperation.LessThan:
					body = Expression.LessThan(memberExpression, propertyValue);
					break;
				case WhereOperation.NotEqual:
					body = Expression.NotEqual(memberExpression, propertyValue);
					break;
				case WhereOperation.Equal:
					body = Expression.Equal(memberExpression, propertyValue);
					break;
				default:
					{
						throw new ArgumentException("Invalid WhereOperation.");
					}

			}
			whereExpression = Expression.Lambda<Func<T, bool>>(body, parameter);
			return whereExpression.Compile();
		}

		public Func<T, TKey> Order<TKey>(ExpressionSortDirection direction)
		{
			Expression<Func<T, TKey>> orderExpression = Expression.Lambda<Func<T, TKey>>(memberExpression, parameter);
			if (direction == ExpressionSortDirection.Ascending)
			{
				return orderExpression.Compile();
			}
			return orderExpression.Compile();
		}

		public Func<T, TKey> Order<TProperty, TKey>(ExpressionSortDirection direction, Func<TProperty, TKey> func)
		{
			var funcExpr = Expression.Call(func.Method, memberExpression);
			var orderExpression = Expression.Lambda<Func<T, TKey>>(funcExpr, parameter);
			if (direction == ExpressionSortDirection.Ascending)
			{
				return orderExpression.Compile();
			}
			return orderExpression.Compile();
		}
	}
	#endregion

}
